{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import scipy.spatial.distance as ssd\n",
    "#计算用户距离\n",
    "import pandas as pd\n",
    "from collections import defaultdict"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#读取训练集，得到列为user_id,item_id,rating"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>3</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>1</td>\n",
       "      <td>7</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>1</td>\n",
       "      <td>8</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>1</td>\n",
       "      <td>9</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>1</td>\n",
       "      <td>11</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>1</td>\n",
       "      <td>13</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>10</th>\n",
       "      <td>1</td>\n",
       "      <td>15</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>11</th>\n",
       "      <td>1</td>\n",
       "      <td>16</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>12</th>\n",
       "      <td>1</td>\n",
       "      <td>18</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>13</th>\n",
       "      <td>1</td>\n",
       "      <td>19</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>14</th>\n",
       "      <td>1</td>\n",
       "      <td>21</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>15</th>\n",
       "      <td>1</td>\n",
       "      <td>22</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>16</th>\n",
       "      <td>1</td>\n",
       "      <td>25</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>17</th>\n",
       "      <td>1</td>\n",
       "      <td>26</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>18</th>\n",
       "      <td>1</td>\n",
       "      <td>28</td>\n",
       "      <td>4</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>19</th>\n",
       "      <td>1</td>\n",
       "      <td>29</td>\n",
       "      <td>1</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "    user_id  item_id  rating\n",
       "0         1        1       5\n",
       "1         1        2       3\n",
       "2         1        3       4\n",
       "3         1        4       3\n",
       "4         1        5       3\n",
       "5         1        7       4\n",
       "6         1        8       1\n",
       "7         1        9       5\n",
       "8         1       11       2\n",
       "9         1       13       5\n",
       "10        1       15       5\n",
       "11        1       16       5\n",
       "12        1       18       4\n",
       "13        1       19       5\n",
       "14        1       21       1\n",
       "15        1       22       4\n",
       "16        1       25       4\n",
       "17        1       26       3\n",
       "18        1       28       4\n",
       "19        1       29       1"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_training_data=pd.read_csv(\"./data/movielen_rating_training.base\",\n",
    "                            names=[\"user_id\",\"item_id\",\"rating\"],usecols=[0,1,2],\n",
    "                            sep=\"\\t\")\n",
    "df_training_data.head(20)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>item1</th>\n",
       "      <th>item2</th>\n",
       "      <th>item3</th>\n",
       "      <th>item4</th>\n",
       "      <th>item5</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>item1</td>\n",
       "      <td>item2</td>\n",
       "      <td>item3</td>\n",
       "      <td>item4</td>\n",
       "      <td>item5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>4</td>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>0</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>2</td>\n",
       "      <td>4</td>\n",
       "      <td>2</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>5</td>\n",
       "      <td>1</td>\n",
       "      <td>5</td>\n",
       "      <td>4</td>\n",
       "      <td>2</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>2</td>\n",
       "      <td>5</td>\n",
       "      <td>3</td>\n",
       "      <td>4</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   item1  item2  item3  item4  item5\n",
       "0  item1  item2  item3  item4  item5\n",
       "1      1      4      2      1      0\n",
       "2      2      4      2      1      5\n",
       "3      5      1      5      4      2\n",
       "4      2      5      3      4      5"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "df_training_data2=pd.read_csv(\"./data/test_data1.csv\",\n",
    "                            names=[\"item1\",\"item2\",\"item3\",\"item4\",\"item5\"],usecols=[0,1,2,3,4])\n",
    "df_training_data2.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "#不重复的user_id与item_id列表\n",
    "user_id_s=df_training_data[\"user_id\"]\n",
    "item_id_s=df_training_data[\"item_id\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "#建立id与index的索引\n",
    "user_index_map={}\n",
    "item_index_map={}\n",
    "for user_index in range(len(user_id_s)):\n",
    "    user_id=user_id_s[user_index]\n",
    "    user_index_map[user_id]=user_index\n",
    "for item_index in range(len(item_id_s)):\n",
    "    item_id = item_id_s[item_index]\n",
    "    item_index_map[item_id] = item_index"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{1: 134,\n",
       " 2: 174,\n",
       " 3: 202,\n",
       " 4: 216,\n",
       " 5: 307,\n",
       " 6: 417,\n",
       " 7: 630,\n",
       " 8: 660,\n",
       " 9: 672,\n",
       " 10: 766,\n",
       " 11: 871,\n",
       " 12: 896,\n",
       " 13: 1269,\n",
       " 14: 1310,\n",
       " 15: 1370,\n",
       " 16: 1439,\n",
       " 17: 1458,\n",
       " 18: 1617,\n",
       " 19: 1627,\n",
       " 20: 1653,\n",
       " 21: 1748,\n",
       " 22: 1818,\n",
       " 23: 1906,\n",
       " 24: 1947,\n",
       " 25: 1988,\n",
       " 26: 2054,\n",
       " 27: 2064,\n",
       " 28: 2103,\n",
       " 29: 2120,\n",
       " 30: 2145,\n",
       " 31: 2168,\n",
       " 32: 2190,\n",
       " 33: 2204,\n",
       " 34: 2214,\n",
       " 35: 2231,\n",
       " 36: 2240,\n",
       " 37: 2277,\n",
       " 38: 2340,\n",
       " 39: 2353,\n",
       " 40: 2375,\n",
       " 41: 2406,\n",
       " 42: 2494,\n",
       " 43: 2606,\n",
       " 44: 2686,\n",
       " 45: 2715,\n",
       " 46: 2726,\n",
       " 47: 2742,\n",
       " 48: 2775,\n",
       " 49: 2882,\n",
       " 50: 2895,\n",
       " 51: 2911,\n",
       " 52: 2946,\n",
       " 53: 2962,\n",
       " 54: 2992,\n",
       " 55: 3002,\n",
       " 56: 3094,\n",
       " 57: 3148,\n",
       " 58: 3228,\n",
       " 59: 3443,\n",
       " 60: 3562,\n",
       " 61: 3574,\n",
       " 62: 3697,\n",
       " 63: 3745,\n",
       " 64: 3854,\n",
       " 65: 3902,\n",
       " 66: 3923,\n",
       " 67: 3935,\n",
       " 68: 3953,\n",
       " 69: 3991,\n",
       " 70: 4068,\n",
       " 71: 4090,\n",
       " 72: 4163,\n",
       " 73: 4197,\n",
       " 74: 4218,\n",
       " 75: 4262,\n",
       " 76: 4307,\n",
       " 77: 4346,\n",
       " 78: 4360,\n",
       " 79: 4387,\n",
       " 80: 4401,\n",
       " 81: 4431,\n",
       " 82: 4517,\n",
       " 83: 4595,\n",
       " 84: 4638,\n",
       " 85: 4797,\n",
       " 86: 4808,\n",
       " 87: 4921,\n",
       " 88: 4932,\n",
       " 89: 4972,\n",
       " 90: 5136,\n",
       " 91: 5186,\n",
       " 92: 5390,\n",
       " 93: 5399,\n",
       " 94: 5620,\n",
       " 95: 5777,\n",
       " 96: 5805,\n",
       " 97: 5840,\n",
       " 98: 5856,\n",
       " 99: 5919,\n",
       " 100: 5953,\n",
       " 101: 5991,\n",
       " 102: 6103,\n",
       " 103: 6118,\n",
       " 104: 6181,\n",
       " 105: 6197,\n",
       " 106: 6225,\n",
       " 107: 6238,\n",
       " 108: 6255,\n",
       " 109: 6389,\n",
       " 110: 6471,\n",
       " 111: 6483,\n",
       " 112: 6507,\n",
       " 113: 6538,\n",
       " 114: 6565,\n",
       " 115: 6614,\n",
       " 116: 6702,\n",
       " 117: 6738,\n",
       " 118: 6780,\n",
       " 119: 6878,\n",
       " 120: 6892,\n",
       " 121: 6938,\n",
       " 122: 6972,\n",
       " 123: 7001,\n",
       " 124: 7015,\n",
       " 125: 7105,\n",
       " 126: 7128,\n",
       " 127: 7139,\n",
       " 128: 7241,\n",
       " 129: 7256,\n",
       " 130: 7434,\n",
       " 131: 7449,\n",
       " 132: 7466,\n",
       " 133: 7484,\n",
       " 134: 7496,\n",
       " 135: 7516,\n",
       " 136: 7536,\n",
       " 137: 7560,\n",
       " 138: 7587,\n",
       " 139: 7602,\n",
       " 140: 7612,\n",
       " 141: 7677,\n",
       " 142: 7697,\n",
       " 143: 7712,\n",
       " 144: 7820,\n",
       " 145: 8005,\n",
       " 146: 8024,\n",
       " 147: 8034,\n",
       " 148: 8067,\n",
       " 149: 8092,\n",
       " 150: 8102,\n",
       " 151: 8268,\n",
       " 152: 8338,\n",
       " 153: 8351,\n",
       " 154: 8378,\n",
       " 155: 8389,\n",
       " 156: 8407,\n",
       " 157: 8434,\n",
       " 158: 8533,\n",
       " 159: 8602,\n",
       " 160: 8668,\n",
       " 161: 8702,\n",
       " 162: 8722,\n",
       " 163: 8735,\n",
       " 164: 8768,\n",
       " 165: 8786,\n",
       " 166: 8796,\n",
       " 167: 8834,\n",
       " 168: 8869,\n",
       " 169: 8892,\n",
       " 170: 8907,\n",
       " 171: 8926,\n",
       " 172: 8935,\n",
       " 173: 8962,\n",
       " 174: 9058,\n",
       " 175: 9081,\n",
       " 176: 9123,\n",
       " 177: 9186,\n",
       " 178: 9339,\n",
       " 179: 9362,\n",
       " 180: 9396,\n",
       " 181: 9614,\n",
       " 182: 9628,\n",
       " 183: 9658,\n",
       " 184: 9791,\n",
       " 185: 9815,\n",
       " 186: 9863,\n",
       " 187: 9897,\n",
       " 188: 9955,\n",
       " 189: 10064,\n",
       " 190: 10100,\n",
       " 191: 10110,\n",
       " 192: 10130,\n",
       " 193: 10191,\n",
       " 194: 10353,\n",
       " 195: 10402,\n",
       " 196: 10423,\n",
       " 197: 10475,\n",
       " 198: 10581,\n",
       " 199: 10600,\n",
       " 200: 10712,\n",
       " 201: 10927,\n",
       " 202: 10940,\n",
       " 203: 10962,\n",
       " 204: 10981,\n",
       " 205: 10991,\n",
       " 206: 11024,\n",
       " 207: 11157,\n",
       " 208: 11168,\n",
       " 209: 11184,\n",
       " 210: 11254,\n",
       " 211: 11275,\n",
       " 212: 11292,\n",
       " 213: 11359,\n",
       " 214: 11422,\n",
       " 215: 11472,\n",
       " 216: 11545,\n",
       " 217: 11582,\n",
       " 218: 11615,\n",
       " 219: 11631,\n",
       " 220: 11641,\n",
       " 221: 11724,\n",
       " 222: 11937,\n",
       " 223: 11989,\n",
       " 224: 12053,\n",
       " 225: 12068,\n",
       " 226: 12099,\n",
       " 227: 12135,\n",
       " 228: 12142,\n",
       " 229: 12157,\n",
       " 230: 12232,\n",
       " 231: 12242,\n",
       " 232: 12289,\n",
       " 233: 12357,\n",
       " 234: 12635,\n",
       " 235: 12682,\n",
       " 236: 12752,\n",
       " 237: 12779,\n",
       " 238: 12793,\n",
       " 239: 12879,\n",
       " 240: 12894,\n",
       " 241: 12906,\n",
       " 242: 12917,\n",
       " 243: 12962,\n",
       " 244: 13079,\n",
       " 245: 13092,\n",
       " 246: 13203,\n",
       " 247: 13218,\n",
       " 248: 13239,\n",
       " 249: 13328,\n",
       " 250: 13393,\n",
       " 251: 13437,\n",
       " 252: 13448,\n",
       " 253: 13504,\n",
       " 254: 13589,\n",
       " 255: 13635,\n",
       " 256: 13750,\n",
       " 257: 13781,\n",
       " 258: 13789,\n",
       " 259: 13816,\n",
       " 260: 13828,\n",
       " 261: 13838,\n",
       " 262: 13920,\n",
       " 263: 13980,\n",
       " 264: 14043,\n",
       " 265: 14070,\n",
       " 266: 14086,\n",
       " 267: 14192,\n",
       " 268: 14371,\n",
       " 269: 14538,\n",
       " 270: 14610,\n",
       " 271: 14771,\n",
       " 272: 14802,\n",
       " 273: 14814,\n",
       " 274: 14853,\n",
       " 275: 14901,\n",
       " 276: 15187,\n",
       " 277: 15215,\n",
       " 278: 15227,\n",
       " 279: 15469,\n",
       " 280: 15616,\n",
       " 281: 15633,\n",
       " 282: 15643,\n",
       " 283: 15671,\n",
       " 284: 15699,\n",
       " 285: 15715,\n",
       " 286: 15873,\n",
       " 287: 15901,\n",
       " 288: 15944,\n",
       " 289: 15957,\n",
       " 290: 16036,\n",
       " 291: 16209,\n",
       " 292: 16265,\n",
       " 293: 16480,\n",
       " 294: 16564,\n",
       " 295: 16664,\n",
       " 296: 16738,\n",
       " 297: 16831,\n",
       " 298: 16909,\n",
       " 299: 17063,\n",
       " 300: 17075,\n",
       " 301: 17226,\n",
       " 302: 17236,\n",
       " 303: 17512,\n",
       " 304: 17525,\n",
       " 305: 17650,\n",
       " 306: 17665,\n",
       " 307: 17719,\n",
       " 308: 17937,\n",
       " 309: 17948,\n",
       " 310: 17952,\n",
       " 311: 18100,\n",
       " 312: 18230,\n",
       " 313: 18383,\n",
       " 314: 18523,\n",
       " 315: 18568,\n",
       " 316: 18612,\n",
       " 317: 18624,\n",
       " 318: 18720,\n",
       " 319: 18736,\n",
       " 320: 18815,\n",
       " 321: 18887,\n",
       " 322: 18914,\n",
       " 323: 18958,\n",
       " 324: 19009,\n",
       " 325: 19085,\n",
       " 326: 19198,\n",
       " 327: 19373,\n",
       " 328: 19542,\n",
       " 329: 19579,\n",
       " 330: 19664,\n",
       " 331: 19704,\n",
       " 332: 19820,\n",
       " 333: 19834,\n",
       " 334: 20052,\n",
       " 335: 20065,\n",
       " 336: 20150,\n",
       " 337: 20171,\n",
       " 338: 20212,\n",
       " 339: 20370,\n",
       " 340: 20397,\n",
       " 341: 20409,\n",
       " 342: 20537,\n",
       " 343: 20694,\n",
       " 344: 20803,\n",
       " 345: 20937,\n",
       " 346: 21071,\n",
       " 347: 21192,\n",
       " 348: 21223,\n",
       " 349: 21251,\n",
       " 350: 21286,\n",
       " 351: 21316,\n",
       " 352: 21345,\n",
       " 353: 21366,\n",
       " 354: 21518,\n",
       " 355: 21538,\n",
       " 356: 21553,\n",
       " 357: 21605,\n",
       " 358: 21640,\n",
       " 359: 21654,\n",
       " 360: 21723,\n",
       " 361: 21801,\n",
       " 362: 21819,\n",
       " 363: 22028,\n",
       " 364: 22042,\n",
       " 365: 22080,\n",
       " 366: 22097,\n",
       " 367: 22132,\n",
       " 368: 22164,\n",
       " 369: 22181,\n",
       " 370: 22237,\n",
       " 371: 22276,\n",
       " 372: 22320,\n",
       " 373: 22476,\n",
       " 374: 22670,\n",
       " 375: 22686,\n",
       " 376: 22708,\n",
       " 377: 22728,\n",
       " 378: 22992,\n",
       " 379: 23128,\n",
       " 380: 23244,\n",
       " 381: 23333,\n",
       " 382: 23366,\n",
       " 383: 23418,\n",
       " 384: 23434,\n",
       " 385: 23636,\n",
       " 386: 23654,\n",
       " 387: 23864,\n",
       " 388: 23906,\n",
       " 389: 24108,\n",
       " 390: 24128,\n",
       " 391: 24223,\n",
       " 392: 24304,\n",
       " 393: 24619,\n",
       " 394: 24744,\n",
       " 395: 24790,\n",
       " 396: 24829,\n",
       " 397: 24909,\n",
       " 398: 25039,\n",
       " 399: 25289,\n",
       " 400: 25306,\n",
       " 401: 25419,\n",
       " 402: 25473,\n",
       " 403: 25520,\n",
       " 404: 25556,\n",
       " 405: 26138,\n",
       " 406: 26412,\n",
       " 407: 26600,\n",
       " 408: 26623,\n",
       " 409: 26778,\n",
       " 410: 26801,\n",
       " 411: 26851,\n",
       " 412: 26888,\n",
       " 413: 26928,\n",
       " 414: 26950,\n",
       " 415: 26971,\n",
       " 416: 27388,\n",
       " 417: 27691,\n",
       " 418: 27706,\n",
       " 419: 27735,\n",
       " 420: 27767,\n",
       " 421: 27822,\n",
       " 422: 27902,\n",
       " 423: 27953,\n",
       " 424: 27993,\n",
       " 425: 28171,\n",
       " 426: 28258,\n",
       " 427: 28282,\n",
       " 428: 28330,\n",
       " 429: 28694,\n",
       " 430: 28755,\n",
       " 431: 28773,\n",
       " 432: 28824,\n",
       " 433: 28861,\n",
       " 434: 28902,\n",
       " 435: 29249,\n",
       " 436: 29375,\n",
       " 437: 29613,\n",
       " 438: 29642,\n",
       " 439: 29670,\n",
       " 440: 29718,\n",
       " 441: 29738,\n",
       " 442: 29862,\n",
       " 443: 29886,\n",
       " 444: 29907,\n",
       " 445: 30029,\n",
       " 446: 30064,\n",
       " 447: 30191,\n",
       " 448: 30226,\n",
       " 449: 30293,\n",
       " 450: 30787,\n",
       " 451: 30878,\n",
       " 452: 31074,\n",
       " 453: 31223,\n",
       " 454: 31448,\n",
       " 455: 31632,\n",
       " 456: 31845,\n",
       " 457: 32114,\n",
       " 458: 32294,\n",
       " 459: 32411,\n",
       " 460: 32478,\n",
       " 461: 32501,\n",
       " 462: 32533,\n",
       " 463: 32666,\n",
       " 464: 32719,\n",
       " 465: 32799,\n",
       " 466: 32900,\n",
       " 467: 32944,\n",
       " 468: 33087,\n",
       " 469: 33130,\n",
       " 470: 33187,\n",
       " 471: 33218,\n",
       " 472: 33481,\n",
       " 473: 33516,\n",
       " 474: 33843,\n",
       " 475: 33863,\n",
       " 476: 33946,\n",
       " 477: 33981,\n",
       " 478: 34094,\n",
       " 479: 34296,\n",
       " 480: 34356,\n",
       " 481: 34412,\n",
       " 482: 34438,\n",
       " 483: 34497,\n",
       " 484: 34636,\n",
       " 485: 34662,\n",
       " 486: 34851,\n",
       " 487: 35082,\n",
       " 488: 35236,\n",
       " 489: 35345,\n",
       " 490: 35402,\n",
       " 491: 35435,\n",
       " 492: 35490,\n",
       " 493: 35625,\n",
       " 494: 35672,\n",
       " 495: 35885,\n",
       " 496: 36014,\n",
       " 497: 36293,\n",
       " 498: 36442,\n",
       " 499: 36544,\n",
       " 500: 36769,\n",
       " 501: 36842,\n",
       " 502: 36879,\n",
       " 503: 37039,\n",
       " 504: 37290,\n",
       " 505: 37402,\n",
       " 506: 37644,\n",
       " 507: 37702,\n",
       " 508: 37789,\n",
       " 509: 37822,\n",
       " 510: 37852,\n",
       " 511: 37876,\n",
       " 512: 37897,\n",
       " 513: 37919,\n",
       " 514: 38113,\n",
       " 515: 38153,\n",
       " 516: 38174,\n",
       " 517: 38211,\n",
       " 518: 38284,\n",
       " 519: 38333,\n",
       " 520: 38356,\n",
       " 521: 38506,\n",
       " 522: 38536,\n",
       " 523: 38636,\n",
       " 524: 38942,\n",
       " 525: 38996,\n",
       " 526: 39064,\n",
       " 527: 39201,\n",
       " 528: 39254,\n",
       " 529: 39297,\n",
       " 530: 39342,\n",
       " 531: 39372,\n",
       " 532: 39646,\n",
       " 533: 39906,\n",
       " 534: 39986,\n",
       " 535: 40204,\n",
       " 536: 40367,\n",
       " 537: 40857,\n",
       " 538: 40938,\n",
       " 539: 40994,\n",
       " 540: 41057,\n",
       " 541: 41190,\n",
       " 542: 41325,\n",
       " 543: 41522,\n",
       " 544: 41553,\n",
       " 545: 41715,\n",
       " 546: 41774,\n",
       " 547: 41797,\n",
       " 548: 41952,\n",
       " 549: 41977,\n",
       " 550: 42017,\n",
       " 551: 42351,\n",
       " 552: 42435,\n",
       " 553: 42535,\n",
       " 554: 42649,\n",
       " 555: 42701,\n",
       " 556: 42745,\n",
       " 557: 42798,\n",
       " 558: 42818,\n",
       " 559: 42894,\n",
       " 560: 42995,\n",
       " 561: 43352,\n",
       " 562: 43424,\n",
       " 563: 43454,\n",
       " 564: 43488,\n",
       " 565: 43523,\n",
       " 566: 43672,\n",
       " 567: 43827,\n",
       " 568: 43908,\n",
       " 569: 43978,\n",
       " 570: 44000,\n",
       " 571: 44020,\n",
       " 572: 44040,\n",
       " 573: 44091,\n",
       " 574: 44137,\n",
       " 575: 44163,\n",
       " 576: 44199,\n",
       " 577: 44387,\n",
       " 578: 44411,\n",
       " 579: 44485,\n",
       " 580: 44532,\n",
       " 581: 44560,\n",
       " 582: 44622,\n",
       " 583: 44649,\n",
       " 584: 44673,\n",
       " 585: 44753,\n",
       " 586: 44919,\n",
       " 587: 45017,\n",
       " 588: 45242,\n",
       " 589: 45285,\n",
       " 590: 45333,\n",
       " 591: 45417,\n",
       " 592: 45777,\n",
       " 593: 45933,\n",
       " 594: 45958,\n",
       " 595: 46054,\n",
       " 596: 46074,\n",
       " 597: 46115,\n",
       " 598: 46140,\n",
       " 599: 46187,\n",
       " 600: 46276,\n",
       " 601: 46424,\n",
       " 602: 46453,\n",
       " 603: 46500,\n",
       " 604: 46527,\n",
       " 605: 46617,\n",
       " 606: 46853,\n",
       " 607: 46890,\n",
       " 608: 47053,\n",
       " 609: 47081,\n",
       " 610: 47156,\n",
       " 611: 47198,\n",
       " 612: 47225,\n",
       " 613: 47253,\n",
       " 614: 47292,\n",
       " 615: 47395,\n",
       " 616: 47438,\n",
       " 617: 47546,\n",
       " 618: 47762,\n",
       " 619: 47851,\n",
       " 620: 47961,\n",
       " 621: 48132,\n",
       " 622: 48360,\n",
       " 623: 48405,\n",
       " 624: 48546,\n",
       " 625: 48652,\n",
       " 626: 48684,\n",
       " 627: 48865,\n",
       " 628: 48892,\n",
       " 629: 49013,\n",
       " 630: 49121,\n",
       " 631: 49141,\n",
       " 632: 49259,\n",
       " 633: 49317,\n",
       " 634: 49452,\n",
       " 635: 49486,\n",
       " 636: 49506,\n",
       " 637: 49610,\n",
       " 638: 49677,\n",
       " 639: 49825,\n",
       " 640: 49934,\n",
       " 641: 49974,\n",
       " 642: 50292,\n",
       " 643: 50498,\n",
       " 644: 50540,\n",
       " 645: 50662,\n",
       " 646: 50700,\n",
       " 647: 50758,\n",
       " 648: 51055,\n",
       " 649: 51079,\n",
       " 650: 51390,\n",
       " 651: 51411,\n",
       " 652: 51433,\n",
       " 653: 51716,\n",
       " 654: 51863,\n",
       " 655: 52548,\n",
       " 656: 52572,\n",
       " 657: 52601,\n",
       " 658: 52672,\n",
       " 659: 52863,\n",
       " 660: 53087,\n",
       " 661: 53208,\n",
       " 662: 53231,\n",
       " 663: 53389,\n",
       " 664: 53555,\n",
       " 665: 53697,\n",
       " 666: 53942,\n",
       " 667: 53989,\n",
       " 668: 54035,\n",
       " 669: 54135,\n",
       " 670: 54181,\n",
       " 671: 54305,\n",
       " 672: 54334,\n",
       " 673: 54369,\n",
       " 674: 54410,\n",
       " 675: 54444,\n",
       " 676: 54521,\n",
       " 677: 54570,\n",
       " 678: 54598,\n",
       " 679: 54660,\n",
       " 680: 54698,\n",
       " 681: 54720,\n",
       " 682: 55119,\n",
       " 683: 55194,\n",
       " 684: 55280,\n",
       " 685: 55300,\n",
       " 686: 55371,\n",
       " 687: 55392,\n",
       " 688: 55416,\n",
       " 689: 55452,\n",
       " 690: 55567,\n",
       " 691: 55599,\n",
       " 692: 55639,\n",
       " 693: 55793,\n",
       " 694: 55950,\n",
       " 695: 55988,\n",
       " 696: 56017,\n",
       " 697: 56122,\n",
       " 698: 56249,\n",
       " 699: 56398,\n",
       " 700: 56419,\n",
       " 701: 56452,\n",
       " 702: 56483,\n",
       " 703: 56530,\n",
       " 704: 56620,\n",
       " 705: 56734,\n",
       " 706: 56763,\n",
       " 707: 56999,\n",
       " 708: 57104,\n",
       " 709: 57242,\n",
       " 710: 57328,\n",
       " 711: 57549,\n",
       " 712: 57711,\n",
       " 713: 57741,\n",
       " 714: 57785,\n",
       " 715: 57952,\n",
       " 716: 58221,\n",
       " 717: 58314,\n",
       " 718: 58353,\n",
       " 719: 58420,\n",
       " 720: 58450,\n",
       " 721: 58618,\n",
       " 722: 58660,\n",
       " 723: 58682,\n",
       " 724: 58767,\n",
       " 725: 58792,\n",
       " 726: 58816,\n",
       " 727: 59138,\n",
       " 728: 59164,\n",
       " 729: 59185,\n",
       " 730: 59223,\n",
       " 731: 59306,\n",
       " 732: 59326,\n",
       " 733: 59433,\n",
       " 734: 59497,\n",
       " 735: 59550,\n",
       " 736: 59574,\n",
       " 737: 59607,\n",
       " 738: 59755,\n",
       " 739: 59790,\n",
       " 740: 59810,\n",
       " 741: 59914,\n",
       " 742: 59940,\n",
       " 743: 59975,\n",
       " 744: 60002,\n",
       " 745: 60062,\n",
       " 746: 60129,\n",
       " 747: 60422,\n",
       " 748: 60530,\n",
       " 749: 60835,\n",
       " 750: 60868,\n",
       " 751: 61036,\n",
       " 752: 61109,\n",
       " 753: 61166,\n",
       " 754: 61200,\n",
       " 755: 61238,\n",
       " 756: 61347,\n",
       " 757: 61513,\n",
       " 758: 61870,\n",
       " 759: 61902,\n",
       " 760: 61943,\n",
       " 761: 62009,\n",
       " 762: 62030,\n",
       " 763: 62159,\n",
       " 764: 62268,\n",
       " 765: 62291,\n",
       " 766: 62466,\n",
       " 767: 62503,\n",
       " 768: 62567,\n",
       " 769: 62596,\n",
       " 770: 62660,\n",
       " 771: 62730,\n",
       " 772: 62763,\n",
       " 773: 62924,\n",
       " 774: 63148,\n",
       " 775: 63176,\n",
       " 776: 63281,\n",
       " 777: 63317,\n",
       " 778: 63382,\n",
       " 779: 63419,\n",
       " 780: 63474,\n",
       " 781: 63516,\n",
       " 782: 63748,\n",
       " 783: 63778,\n",
       " 784: 63817,\n",
       " 785: 63844,\n",
       " 786: 63961,\n",
       " 787: 64018,\n",
       " 788: 64267,\n",
       " 789: 64300,\n",
       " 790: 64531,\n",
       " 791: 64556,\n",
       " 792: 64603,\n",
       " 793: 64658,\n",
       " 794: 64697,\n",
       " 795: 64856,\n",
       " 796: 65214,\n",
       " 797: 65240,\n",
       " 798: 65479,\n",
       " 799: 65503,\n",
       " 800: 65531,\n",
       " 801: 65557,\n",
       " 802: 65632,\n",
       " 803: 65665,\n",
       " 804: 65997,\n",
       " 805: 66270,\n",
       " 806: 66410,\n",
       " 807: 66614,\n",
       " 808: 66637,\n",
       " 809: 66657,\n",
       " 810: 66683,\n",
       " 811: 66704,\n",
       " 812: 66724,\n",
       " 813: 66753,\n",
       " 814: 66788,\n",
       " 815: 66971,\n",
       " 816: 66996,\n",
       " 817: 67032,\n",
       " 818: 67053,\n",
       " 819: 67081,\n",
       " 820: 67102,\n",
       " 821: 67164,\n",
       " 822: 67189,\n",
       " 823: 67374,\n",
       " 824: 67394,\n",
       " 825: 67539,\n",
       " 826: 67654,\n",
       " 827: 67682,\n",
       " 828: 67786,\n",
       " 829: 67850,\n",
       " 830: 67956,\n",
       " 831: 68029,\n",
       " 832: 68054,\n",
       " 833: 68321,\n",
       " 834: 68375,\n",
       " 835: 68477,\n",
       " 836: 68527,\n",
       " 837: 68573,\n",
       " 838: 68666,\n",
       " 839: 68723,\n",
       " 840: 68920,\n",
       " 841: 68951,\n",
       " 842: 68978,\n",
       " 843: 69182,\n",
       " 844: 69263,\n",
       " 845: 69294,\n",
       " 846: 69699,\n",
       " 847: 69845,\n",
       " 848: 69995,\n",
       " 849: 70018,\n",
       " 850: 70069,\n",
       " 851: 70278,\n",
       " 852: 70327,\n",
       " 853: 70368,\n",
       " 854: 70585,\n",
       " 855: 70608,\n",
       " 856: 70634,\n",
       " 857: 70656,\n",
       " 858: 70677,\n",
       " 859: 70716,\n",
       " 860: 70787,\n",
       " 861: 70830,\n",
       " 862: 70995,\n",
       " 863: 71102,\n",
       " 864: 71396,\n",
       " 865: 71462,\n",
       " 866: 71482,\n",
       " 867: 71577,\n",
       " 868: 71785,\n",
       " 869: 71832,\n",
       " 870: 72101,\n",
       " 871: 72216,\n",
       " 872: 72287,\n",
       " 873: 72307,\n",
       " 874: 72341,\n",
       " 875: 72430,\n",
       " 876: 72451,\n",
       " 877: 72532,\n",
       " 878: 72666,\n",
       " 879: 72695,\n",
       " 880: 73063,\n",
       " 881: 73322,\n",
       " 882: 73459,\n",
       " 883: 73727,\n",
       " 884: 73770,\n",
       " 885: 73872,\n",
       " 886: 74112,\n",
       " 887: 74283,\n",
       " 888: 74303,\n",
       " 889: 74629,\n",
       " 890: 74748,\n",
       " 891: 74795,\n",
       " 892: 75021,\n",
       " 893: 75080,\n",
       " 894: 75325,\n",
       " 895: 75345,\n",
       " 896: 75707,\n",
       " 897: 75892,\n",
       " 898: 75922,\n",
       " 899: 76057,\n",
       " 900: 76102,\n",
       " 901: 76226,\n",
       " 902: 76275,\n",
       " 903: 76411,\n",
       " 904: 76458,\n",
       " 905: 76498,\n",
       " 906: 76539,\n",
       " 907: 76686,\n",
       " 908: 76760,\n",
       " 909: 76786,\n",
       " 910: 76846,\n",
       " 911: 76944,\n",
       " 912: 76997,\n",
       " 913: 77129,\n",
       " 914: 77152,\n",
       " 915: 77178,\n",
       " 916: 77495,\n",
       " 917: 77530,\n",
       " 918: 77633,\n",
       " 919: 77850,\n",
       " 920: 77876,\n",
       " 921: 77986,\n",
       " 922: 78113,\n",
       " 923: 78187,\n",
       " 924: 78269,\n",
       " 925: 78301,\n",
       " 926: 78321,\n",
       " 927: 78441,\n",
       " 928: 78473,\n",
       " 929: 78522,\n",
       " 930: 78585,\n",
       " 931: 78646,\n",
       " 932: 78887,\n",
       " 933: 79071,\n",
       " 934: 79245,\n",
       " 935: 79284,\n",
       " 936: 79426,\n",
       " 937: 79466,\n",
       " 938: 79574,\n",
       " 939: 79623,\n",
       " 940: 79730,\n",
       " 941: 79752,\n",
       " 942: 79831,\n",
       " 943: 79999}"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "user_index_map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "ename": "MemoryError",
     "evalue": "Unable to allocate 47.7 GiB for an array with shape (80000, 80000) and data type float64",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mMemoryError\u001b[0m                               Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-12-3bbdeb838722>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m#用户与物品的打分矩阵\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0muser_item_rating_array\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mshape\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mitem_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[1;31m#用户打分商品的索引集合\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m \u001b[0muser_rating_map\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mdefaultdict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mset\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mMemoryError\u001b[0m: Unable to allocate 47.7 GiB for an array with shape (80000, 80000) and data type float64"
     ]
    }
   ],
   "source": [
    "#用户与物品的打分矩阵\n",
    "user_item_rating_array = np.zeros(shape=(len(user_id_s),len(item_id_s)))\n",
    "\n",
    "#用户打分商品的索引集合,dict元素值是空索引\n",
    "user_rating_map=defaultdict(set)\n",
    "\n",
    "for row_index in df_training_data.index:\n",
    "    row_data=df_training_data.iloc[row_index]\n",
    "    #打分用户的索引\n",
    "    user_index=user_idex_map[row_data[\"user_id\"]]\n",
    "    #打分电影的索引\n",
    "    item_index=item_index_map[row_data[\"item_id\"]]\n",
    "    #添加用户打分商品索引集合\n",
    "    user_rating_map[user_index].add(item_index)\n",
    "    user_item_rating_array[user_index,item_index]=row_data[\"rating\"]\n",
    "user_item_rating_array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'user_item_rating_array' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-14-f4d5fda41dbb>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     14\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     15\u001b[0m \u001b[1;31m#计算用户的平均打分\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 16\u001b[1;33m \u001b[0muser_rating_mu_s\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mcalculate_user_rating_mu\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     17\u001b[0m \u001b[0muser_rating_mu_s\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-14-f4d5fda41dbb>\u001b[0m in \u001b[0;36mcalculate_user_rating_mu\u001b[1;34m()\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[1;32mfor\u001b[0m \u001b[0muser_index\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m         \u001b[1;31m#计算打过分的电影索引\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m         item_rating_v=np.take(user_item_rating_array[user_index],\n\u001b[0m\u001b[0;32m      7\u001b[0m         item_rating_index_v)\n\u001b[0;32m      8\u001b[0m         \u001b[1;31m#打分向量的平均值\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'user_item_rating_array' is not defined"
     ]
    }
   ],
   "source": [
    "#计算用户的平均打分向量\n",
    "def calculate_user_rating_mu():\n",
    "    user_rating_mu_s=[]\n",
    "    for user_index in range(len(user_id_s)):\n",
    "        #计算打过分的电影索引\n",
    "        item_rating_v=np.take(user_item_rating_array[user_index],\n",
    "        item_rating_index_v)\n",
    "        #打分向量的平均值\n",
    "        mu=item_rating_index_v.mean()\n",
    "        #保留两位小数\n",
    "        mu=round(mu,2)\n",
    "        user_rating_mu_s.append(mu)\n",
    "    return user_rating_mu_s\n",
    "\n",
    "#计算用户的平均打分\n",
    "user_rating_mu_s=calculate_user_rating_mu()\n",
    "user_rating_mu_s"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "ename": "SyntaxError",
     "evalue": "unexpected EOF while parsing (<ipython-input-15-9fb2bfd5bfeb>, line 1)",
     "output_type": "error",
     "traceback": [
      "\u001b[1;36m  File \u001b[1;32m\"<ipython-input-15-9fb2bfd5bfeb>\"\u001b[1;36m, line \u001b[1;32m1\u001b[0m\n\u001b[1;33m    def calculate_sim(user_index1,user_index2):\u001b[0m\n\u001b[1;37m                                               ^\u001b[0m\n\u001b[1;31mSyntaxError\u001b[0m\u001b[1;31m:\u001b[0m unexpected EOF while parsing\n"
     ]
    }
   ],
   "source": [
    "#定义用户相似度\n",
    "def calculate_sim(user_index1,user_index2):\n",
    "    #取用户1和用户2公共打分的电影集合，装换成列表\n",
    "    intersection_index_s = list(\n",
    "        user_rating_map[user_index1] & user_rating_map[user_index2]\n",
    "    )\n",
    "    #如果没有公共的打分项，相似度为0\n",
    "    if not intersection_index_s：\n",
    "        return 0.0\n",
    "    #根据公共索引，渠道用户的打分向量，并且去均值\n",
    "    v1=np.take(\n",
    "     user_item_rating_array[user_index1],\n",
    "     intersection_index_s\n",
    "    )-user_rating_mu_s[user_index1]\n",
    "    v2=np.take(\n",
    "     user_item_rating_array[user_index2],\n",
    "     intersection_index_s\n",
    "    )-user_rating_mu_s[user_index2]\n",
    "    # 计算相似度\n",
    "    sim = 1 - ssd.cosine(v1,v2)\n",
    "    # 如果相似度不是数字（如果v1或v2是0向量），返回相似度0\n",
    "    if np.isnan(sim):\n",
    "        return 0.0\n",
    "    # 否则相似度保留两位小数，返回结果\n",
    "    else:\n",
    "        return round(sim,2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [
    {
     "ename": "MemoryError",
     "evalue": "Unable to allocate 47.7 GiB for an array with shape (80000, 80000) and data type float64",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mMemoryError\u001b[0m                               Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-16-ce958ba53bfc>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0muser_similarity_array\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mzeros\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mshape\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      2\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0muser_index1\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      3\u001b[0m     \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"计算用户：%s与其余用户的相似度\"\u001b[0m\u001b[1;33m%\u001b[0m\u001b[0muser_index1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[1;32mfor\u001b[0m \u001b[0muser_index2\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_index1\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m         \u001b[1;31m#计算用户1与用户2的相似度\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mMemoryError\u001b[0m: Unable to allocate 47.7 GiB for an array with shape (80000, 80000) and data type float64"
     ]
    }
   ],
   "source": [
    "user_similarity_array = np.zeros(shape=(len(user_id_s),len(user_id_s)))\n",
    "for user_index1 in range(len(user_id_s)):\n",
    "    print(\"计算用户：%s与其余用户的相似度\"%user_index1)\n",
    "    for user_index2 in range(user_index1 + 1,len(user_id_s)):\n",
    "        #计算用户1与用户2的相似度\n",
    "        sim = calculate_sim(user_index1,user_index2)\n",
    "        user_similarity_array[user_index1,user_index2]=sim\n",
    "        user_similarity_array[user_index2,user_index1]=sim\n",
    "\n",
    "user_similarity_array"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'user_item_rating_array' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-17-1ba108958f2f>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      1\u001b[0m \u001b[1;31m#用户对商品的预测矩阵，已经打分的商品，预测的分数为0分\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 2\u001b[1;33m \u001b[0muser_item_predict_rating_array\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mzeros_like\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_item_rating_array\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      3\u001b[0m \u001b[1;31m#对所有的用户index进行遍历\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      4\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0muser_index\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'预测到用户%s'\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0muser_index\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'user_item_rating_array' is not defined"
     ]
    }
   ],
   "source": [
    "#用户对商品的预测矩阵，已经打分的商品，预测的分数为0分\n",
    "#用户没有打过分的商品，进行预测\n",
    "user_item_predict_rating_array = np.zeros_like(user_item_rating_array)\n",
    "#对所有的用户index进行遍历\n",
    "for user_index in range(len(user_id_s)):\n",
    "    print('预测到用户%s' % user_index)\n",
    "    # 对所有商品进行遍历\n",
    "    for item_index in range(len(item_id_s)):\n",
    "        # 如果这个商品没有被打过分，用户没有对这个商品打过分，则可以预测这个商品\n",
    "        if item_index not in user_rating_map[user_index]:\n",
    "            # 找到对这个商品打过分的所有用户的索引\n",
    "            user_rating_index_v = np.where(\n",
    "                user_item_rating_array[:,item_index] > 0\n",
    "            )[0]\n",
    "            # 如果没有用户对这个商品打过分，continue\n",
    "            if not list(user_rating_index_v):\n",
    "                continue\n",
    "            # 根据用户打分的索引，从用户相似度矩阵中取出相似度向量\n",
    "            user_sim_v = np.take(\n",
    "                user_similarity_array[user_index],\n",
    "                user_rating_index_v,\n",
    "            )\n",
    "            # 计算相似度绝对值加和\n",
    "            user_sim_abs_sum = user_sim_v.__abs__().sum()\n",
    "            # 如果相似度绝对值加和为0（也就是存在对这个商品打过分的用户群体，但这些用户群体与目标用户的相关度都为0），continue\n",
    "            if user_sim_abs_sum == 0:\n",
    "                continue\n",
    "            # 得到用户打分的向量，并去掉平均值\n",
    "            user_rating_v = np.take(\n",
    "                user_item_rating_array[:,item_index],\n",
    "                user_rating_index_v\n",
    "            ) - np.take(\n",
    "                user_rating_mu_s,\n",
    "                user_rating_index_v\n",
    "            )\n",
    "            # 根据公式，得到预测的结果，这里保留两位小数\n",
    "#             predict_rating = round(\n",
    "#                 (np.dot(user_rating_v,user_sim_v) + user_rating_mu_s[user_index])/user_sim_abs_sum\n",
    "#                 ,2\n",
    "#             ) + user_rating_mu_s[user_index]\n",
    "            predict_rating = round(\n",
    "                np.dot(user_rating_v,user_sim_v)/user_sim_abs_sum\n",
    "                ,2\n",
    "            ) + user_rating_mu_s[user_index]\n",
    "            # 把预测的结果添加到预测矩阵中\n",
    "            user_item_predict_rating_array[user_index,item_index] = predict_rating\n",
    "# 打印预测矩阵\n",
    "user_item_predict_rating_array    "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>user_id</th>\n",
       "      <th>item_id</th>\n",
       "      <th>rating</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>1</td>\n",
       "      <td>6</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>1</td>\n",
       "      <td>10</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>1</td>\n",
       "      <td>12</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>1</td>\n",
       "      <td>14</td>\n",
       "      <td>5</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>1</td>\n",
       "      <td>17</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   user_id  item_id  rating\n",
       "0        1        6       5\n",
       "1        1       10       3\n",
       "2        1       12       5\n",
       "3        1       14       5\n",
       "4        1       17       3"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "#读取测试集合\n",
    "df_test_data = pd.read_csv('./data/movielen_rating_test.base',sep='\\t',names=['user_id','item_id','rating'],usecols=[0,1,2])\n",
    "df_test_data.head()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[134,\n",
       " 174,\n",
       " 202,\n",
       " 216,\n",
       " 307,\n",
       " 417,\n",
       " 630,\n",
       " 660,\n",
       " 672,\n",
       " 766,\n",
       " 871,\n",
       " 896,\n",
       " 1269,\n",
       " 1310,\n",
       " 1370,\n",
       " 1439,\n",
       " 1458,\n",
       " 1617,\n",
       " 1627,\n",
       " 1653,\n",
       " 1748,\n",
       " 1818,\n",
       " 1906,\n",
       " 1947,\n",
       " 1988,\n",
       " 2054,\n",
       " 2064,\n",
       " 2103,\n",
       " 2120,\n",
       " 2145,\n",
       " 2168,\n",
       " 2190,\n",
       " 2204,\n",
       " 2214,\n",
       " 2231,\n",
       " 2240,\n",
       " 2277,\n",
       " 2340,\n",
       " 2353,\n",
       " 2375,\n",
       " 2406,\n",
       " 2494,\n",
       " 2606,\n",
       " 2686,\n",
       " 2715,\n",
       " 2726,\n",
       " 2742,\n",
       " 2775,\n",
       " 2882,\n",
       " 2895,\n",
       " 2911,\n",
       " 2946,\n",
       " 2962,\n",
       " 2992,\n",
       " 3002,\n",
       " 3094,\n",
       " 3148,\n",
       " 3228,\n",
       " 3443,\n",
       " 3562,\n",
       " 3574,\n",
       " 3697,\n",
       " 3745,\n",
       " 3854,\n",
       " 3902,\n",
       " 3923,\n",
       " 3935,\n",
       " 3953,\n",
       " 3991,\n",
       " 4068,\n",
       " 4090,\n",
       " 4163,\n",
       " 4197,\n",
       " 4218,\n",
       " 4262,\n",
       " 4307,\n",
       " 4346,\n",
       " 4360,\n",
       " 4387,\n",
       " 4401,\n",
       " 4431,\n",
       " 4517,\n",
       " 4595,\n",
       " 4638,\n",
       " 4797,\n",
       " 4808,\n",
       " 4921,\n",
       " 4932,\n",
       " 4972,\n",
       " 5136,\n",
       " 5186,\n",
       " 5390,\n",
       " 5399,\n",
       " 5620,\n",
       " 5777,\n",
       " 5805,\n",
       " 5840,\n",
       " 5856,\n",
       " 5919,\n",
       " 5953,\n",
       " 5991,\n",
       " 6103,\n",
       " 6118,\n",
       " 6181,\n",
       " 6197,\n",
       " 6225,\n",
       " 6238,\n",
       " 6255,\n",
       " 6389,\n",
       " 6471,\n",
       " 6483,\n",
       " 6507,\n",
       " 6538,\n",
       " 6565,\n",
       " 6614,\n",
       " 6702,\n",
       " 6738,\n",
       " 6780,\n",
       " 6878,\n",
       " 6892,\n",
       " 6938,\n",
       " 6972,\n",
       " 7001,\n",
       " 7015,\n",
       " 7105,\n",
       " 7128,\n",
       " 7139,\n",
       " 7241,\n",
       " 7256,\n",
       " 7434,\n",
       " 7449,\n",
       " 7466,\n",
       " 7484,\n",
       " 7496,\n",
       " 7516,\n",
       " 7536,\n",
       " 7560,\n",
       " 7587,\n",
       " 7602,\n",
       " 7612,\n",
       " 7677,\n",
       " 7697,\n",
       " 7712,\n",
       " 7820,\n",
       " 8005,\n",
       " 8024,\n",
       " 8034,\n",
       " 8067,\n",
       " 8092,\n",
       " 8102,\n",
       " 8268,\n",
       " 8338,\n",
       " 8351,\n",
       " 8378,\n",
       " 8389,\n",
       " 8407,\n",
       " 8434,\n",
       " 8533,\n",
       " 8602,\n",
       " 8668,\n",
       " 8702,\n",
       " 8722,\n",
       " 8735,\n",
       " 8768,\n",
       " 8786,\n",
       " 8796,\n",
       " 8834,\n",
       " 8869,\n",
       " 8892,\n",
       " 8907,\n",
       " 8926,\n",
       " 8935,\n",
       " 8962,\n",
       " 9058,\n",
       " 9081,\n",
       " 9123,\n",
       " 9186,\n",
       " 9339,\n",
       " 9362,\n",
       " 9396,\n",
       " 9614,\n",
       " 9628,\n",
       " 9658,\n",
       " 9791,\n",
       " 9815,\n",
       " 9863,\n",
       " 9897,\n",
       " 9955,\n",
       " 10064,\n",
       " 10100,\n",
       " 10110,\n",
       " 10130,\n",
       " 10191,\n",
       " 10353,\n",
       " 10402,\n",
       " 10423,\n",
       " 10475,\n",
       " 10581,\n",
       " 10600,\n",
       " 10712,\n",
       " 10927,\n",
       " 10940,\n",
       " 10962,\n",
       " 10981,\n",
       " 10991,\n",
       " 11024,\n",
       " 11157,\n",
       " 11168,\n",
       " 11184,\n",
       " 11254,\n",
       " 11275,\n",
       " 11292,\n",
       " 11359,\n",
       " 11422,\n",
       " 11472,\n",
       " 11545,\n",
       " 11582,\n",
       " 11615,\n",
       " 11631,\n",
       " 11641,\n",
       " 11724,\n",
       " 11937,\n",
       " 11989,\n",
       " 12053,\n",
       " 12068,\n",
       " 12099,\n",
       " 12135,\n",
       " 12142,\n",
       " 12157,\n",
       " 12232,\n",
       " 12242,\n",
       " 12289,\n",
       " 12357,\n",
       " 12635,\n",
       " 12682,\n",
       " 12752,\n",
       " 12779,\n",
       " 12793,\n",
       " 12879,\n",
       " 12894,\n",
       " 12906,\n",
       " 12917,\n",
       " 12962,\n",
       " 13079,\n",
       " 13092,\n",
       " 13203,\n",
       " 13218,\n",
       " 13239,\n",
       " 13328,\n",
       " 13393,\n",
       " 13437,\n",
       " 13448,\n",
       " 13504,\n",
       " 13589,\n",
       " 13635,\n",
       " 13750,\n",
       " 13781,\n",
       " 13789,\n",
       " 13816,\n",
       " 13828,\n",
       " 13838,\n",
       " 13920,\n",
       " 13980,\n",
       " 14043,\n",
       " 14070,\n",
       " 14086,\n",
       " 14192,\n",
       " 14371,\n",
       " 14538,\n",
       " 14610,\n",
       " 14771,\n",
       " 14802,\n",
       " 14814,\n",
       " 14853,\n",
       " 14901,\n",
       " 15187,\n",
       " 15215,\n",
       " 15227,\n",
       " 15469,\n",
       " 15616,\n",
       " 15633,\n",
       " 15643,\n",
       " 15671,\n",
       " 15699,\n",
       " 15715,\n",
       " 15873,\n",
       " 15901,\n",
       " 15944,\n",
       " 15957,\n",
       " 16036,\n",
       " 16209,\n",
       " 16265,\n",
       " 16480,\n",
       " 16564,\n",
       " 16664,\n",
       " 16738,\n",
       " 16831,\n",
       " 16909,\n",
       " 17063,\n",
       " 17075,\n",
       " 17226,\n",
       " 17236,\n",
       " 17512,\n",
       " 17525,\n",
       " 17650,\n",
       " 17665,\n",
       " 17719,\n",
       " 17937,\n",
       " 17948,\n",
       " 17952,\n",
       " 18100,\n",
       " 18230,\n",
       " 18383,\n",
       " 18523,\n",
       " 18568,\n",
       " 18612,\n",
       " 18624,\n",
       " 18720,\n",
       " 18736,\n",
       " 18815,\n",
       " 18887,\n",
       " 18914,\n",
       " 18958,\n",
       " 19009,\n",
       " 19085,\n",
       " 19198,\n",
       " 19373,\n",
       " 19542,\n",
       " 19579,\n",
       " 19664,\n",
       " 19704,\n",
       " 19820,\n",
       " 19834,\n",
       " 20052,\n",
       " 20065,\n",
       " 20150,\n",
       " 20171,\n",
       " 20212,\n",
       " 20370,\n",
       " 20397,\n",
       " 20409,\n",
       " 20537,\n",
       " 20694,\n",
       " 20803,\n",
       " 20937,\n",
       " 21071,\n",
       " 21192,\n",
       " 21223,\n",
       " 21251,\n",
       " 21286,\n",
       " 21316,\n",
       " 21345,\n",
       " 21366,\n",
       " 21518,\n",
       " 21538,\n",
       " 21553,\n",
       " 21605,\n",
       " 21640,\n",
       " 21654,\n",
       " 21723,\n",
       " 21801,\n",
       " 21819,\n",
       " 22028,\n",
       " 22042,\n",
       " 22080,\n",
       " 22097,\n",
       " 22132,\n",
       " 22164,\n",
       " 22181,\n",
       " 22237,\n",
       " 22276,\n",
       " 22320,\n",
       " 22476,\n",
       " 22670,\n",
       " 22686,\n",
       " 22708,\n",
       " 22728,\n",
       " 22992,\n",
       " 23128,\n",
       " 23244,\n",
       " 23333,\n",
       " 23366,\n",
       " 23418,\n",
       " 23434,\n",
       " 23636,\n",
       " 23654,\n",
       " 23864,\n",
       " 23906,\n",
       " 24108,\n",
       " 24128,\n",
       " 24223,\n",
       " 24304,\n",
       " 24619,\n",
       " 24744,\n",
       " 24790,\n",
       " 24829,\n",
       " 24909,\n",
       " 25039,\n",
       " 25289,\n",
       " 25306,\n",
       " 25419,\n",
       " 25473,\n",
       " 25520,\n",
       " 25556,\n",
       " 26138,\n",
       " 26412,\n",
       " 26600,\n",
       " 26623,\n",
       " 26778,\n",
       " 26801,\n",
       " 26851,\n",
       " 26888,\n",
       " 26928,\n",
       " 26950,\n",
       " 26971,\n",
       " 27388,\n",
       " 27691,\n",
       " 27706,\n",
       " 27735,\n",
       " 27767,\n",
       " 27822,\n",
       " 27902,\n",
       " 27953,\n",
       " 27993,\n",
       " 28171,\n",
       " 28258,\n",
       " 28282,\n",
       " 28330,\n",
       " 28694,\n",
       " 28755,\n",
       " 28773,\n",
       " 28824,\n",
       " 28861,\n",
       " 28902,\n",
       " 29249,\n",
       " 29375,\n",
       " 29613,\n",
       " 29642,\n",
       " 29670,\n",
       " 29718,\n",
       " 29862,\n",
       " 29907,\n",
       " 30029,\n",
       " 30064,\n",
       " 30191,\n",
       " 30226,\n",
       " 30293,\n",
       " 30787,\n",
       " 30878,\n",
       " 31074,\n",
       " 31223,\n",
       " 31448,\n",
       " 31632,\n",
       " 31845,\n",
       " 32114,\n",
       " 32294,\n",
       " 32411,\n",
       " 32478,\n",
       " 32533]"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "user_test_unique_s = df_test_data['user_id'].unique()#测试集合中吧重复的用户id\n",
    "# 创建一个列表，保存测试集中的user_id对应的user_index\n",
    "user_index_test_s = []\n",
    "# 对测试集中的用户id进行遍历\n",
    "for user_id in user_test_unique_s:\n",
    "    # 如果测试集中的用户id在训练集的用户索引map中，添加这个user_index\n",
    "    if user_id in user_index_map.keys():\n",
    "        user_index_test_s.append(user_index_map[user_id])\n",
    "# 打印测试集中的user_index列表\n",
    "user_index_test_s\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "运行到0行\n"
     ]
    },
    {
     "ename": "NameError",
     "evalue": "name 'user_rating_map' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-20-355c153c5582>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      8\u001b[0m     \u001b[0mrow_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mdf_test_data\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mloc\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mrow_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      9\u001b[0m     \u001b[1;31m# 如果这个用户id在user_rating_map中，商品id也在item_index_map中，添加这次打分\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m     \u001b[1;32mif\u001b[0m \u001b[0mrow_data\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'user_id'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;32min\u001b[0m \u001b[0muser_rating_map\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;32mand\u001b[0m \u001b[0mrow_data\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'item_id'\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mitem_index_map\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     11\u001b[0m         \u001b[0mdf_user_item_rating_test\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mitem_index_map\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mrow_data\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'item_id'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0muser_index_map\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mrow_data\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'user_id'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m]\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mrow_data\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'rating'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     12\u001b[0m \u001b[1;31m# 打印dataframe\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'user_rating_map' is not defined"
     ]
    }
   ],
   "source": [
    "# 创建一个用户对商品打分的dataframe\n",
    "df_user_item_rating_test = pd.DataFrame(np.zeros(shape=(len(user_index_test_s),len(item_id_s))))\n",
    "# dataframe的index设置为在训练集中存在的测试集的user_index\n",
    "df_user_item_rating_test.index = user_index_test_s\n",
    "# 对dataframe的index进行遍历\n",
    "for row_index in df_test_data.index:\n",
    "    print('运行到%s行'% row_index)\n",
    "    row_data = df_test_data.loc[row_index]\n",
    "    # 如果这个用户id在user_rating_map中，商品id也在item_index_map中，添加这次打分\n",
    "    if row_data['user_id'] in user_rating_map.keys() and row_data['item_id'] in item_index_map.keys():\n",
    "        df_user_item_rating_test[item_index_map[row_data['item_id']]][user_index_map[row_data['user_id']]] = row_data['rating']\n",
    "# 打印dataframe\n",
    "df_user_item_rating_test"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'user_item_predict_rating_array' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-21-4f67bb4437c5>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     34\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msqrt\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0macc_loss\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0macc_num\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     35\u001b[0m \u001b[1;31m# 计算均方误差并打印\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 36\u001b[1;33m \u001b[0mRMSE\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcalculate_RMSE\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     37\u001b[0m \u001b[0mRMSE\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-21-4f67bb4437c5>\u001b[0m in \u001b[0;36mcalculate_RMSE\u001b[1;34m()\u001b[0m\n\u001b[0;32m     10\u001b[0m         \u001b[0mtest_row_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0marray\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdf_user_item_rating_test\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mloc\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0muser_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     11\u001b[0m         \u001b[1;31m# 预测矩阵中的行向量\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 12\u001b[1;33m         \u001b[0mpredict_row_data\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0muser_item_predict_rating_array\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0muser_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     13\u001b[0m         \u001b[1;31m# 测试集中对应user_index，打过分的商品索引\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     14\u001b[0m         \u001b[0mtest_index_v\u001b[0m \u001b[1;33m=\u001b[0m  \u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mwhere\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtest_row_data\u001b[0m \u001b[1;33m>\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'user_item_predict_rating_array' is not defined"
     ]
    }
   ],
   "source": [
    "# 计算均方误差\n",
    "def calculate_RMSE():\n",
    "    # acc_locc为分子，二次损失\n",
    "    acc_loss = 0\n",
    "    # acc_num为分母，一共计算了多少项\n",
    "    acc_num = 0\n",
    "    # 对测试集的index进行遍历\n",
    "    for user_index in df_user_item_rating_test.index:\n",
    "        # 测试集中user_index对应的行向量\n",
    "        test_row_data = np.array(df_user_item_rating_test.loc[user_index])\n",
    "        # 预测矩阵中的行向量\n",
    "        predict_row_data = user_item_predict_rating_array[user_index]\n",
    "        # 测试集中对应user_index，打过分的商品索引\n",
    "        test_index_v =  np.where(test_row_data > 0)\n",
    "        # 预测矩阵中对应user_index，打过分的商品索引\n",
    "        predict_index_v = np.where(predict_row_data > 0)\n",
    "        # 取test_index_v和predict_index_v的交集，即预测过打分，而且也在测试集中出现实际打分\n",
    "        intersection_index_s = list(\n",
    "            set(test_index_v[0]) & set(predict_index_v[0])\n",
    "        )\n",
    "        # 如果交集为空，continue\n",
    "        if not intersection_index_s:\n",
    "            continue\n",
    "        # 根据上述的交集索引，取得测试集中的打分向量和预测矩阵中的打分向量\n",
    "        test_rating_v = np.take(test_row_data,intersection_index_s)\n",
    "        predict_rating_v = np.clip(\n",
    "            np.take(predict_row_data,intersection_index_s),0,5\n",
    "        )\n",
    "        # 计算二次损失\n",
    "        acc_loss += np.square(test_rating_v - predict_rating_v).sum()\n",
    "        # 分母叠加个数\n",
    "        acc_num += len(intersection_index_s)\n",
    "    # 得出均方误差\n",
    "    return np.sqrt(acc_loss/acc_num)\n",
    "# 计算均方误差并打印\n",
    "RMSE = calculate_RMSE()\n",
    "RMSE"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'user_item_predict_rating_array' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-22-ead3ea0840a2>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     15\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[0mpredict_item_index_map\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     16\u001b[0m \u001b[1;31m# 推荐50个商品\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 17\u001b[1;33m \u001b[0mpredict_item_index_map\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpredict\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m50\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     18\u001b[0m \u001b[1;31m# 打印商品推荐字典\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     19\u001b[0m \u001b[0mpredict_item_index_map\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-22-ead3ea0840a2>\u001b[0m in \u001b[0;36mpredict\u001b[1;34m(predict_quantity)\u001b[0m\n\u001b[0;32m      7\u001b[0m     \u001b[1;32mfor\u001b[0m \u001b[0muser_index\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0muser_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      8\u001b[0m         \u001b[1;31m# 预测矩阵中对应user_index的向量，进行倒序排列\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 9\u001b[1;33m         \u001b[0mpredict_item_index_v\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mlist\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0margsort\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0muser_item_predict_rating_array\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0muser_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     10\u001b[0m         \u001b[1;31m# 取min(min(predict_quantity,len(predict_item_index_v)))个最前面的商品索引，即打分最高的商品索引\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     11\u001b[0m         \u001b[0mpredict_item_index_v\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mpredict_item_index_v\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[0mmin\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpredict_quantity\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpredict_item_index_v\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'user_item_predict_rating_array' is not defined"
     ]
    }
   ],
   "source": [
    "# 推荐商品，predict_quantity是推荐的商品的个数\n",
    "def predict(predict_quantity):\n",
    "    # 建立一个商品推荐字典,保存对user_index推荐的商品索引\n",
    "    # 例如：predict_item_index_map[user_index] = [4,3,2,5] \n",
    "    predict_item_index_map = {}\n",
    "    # 对训练集中所有的user_index进行遍历\n",
    "    for user_index in range(len(user_id_s)):\n",
    "        # 预测矩阵中对应user_index的向量，进行倒序排列\n",
    "        predict_item_index_v = list(np.argsort(-user_item_predict_rating_array[user_index]))\n",
    "        # 取min(min(predict_quantity,len(predict_item_index_v)))个最前面的商品索引，即打分最高的商品索引\n",
    "        predict_item_index_v = predict_item_index_v[0:min(predict_quantity,len(predict_item_index_v))]\n",
    "        # 添加到商品推荐字典中\n",
    "        predict_item_index_map[user_index] = predict_item_index_v\n",
    "    # 返回商品推荐字典\n",
    "    return predict_item_index_map\n",
    "# 推荐50个商品\n",
    "predict_item_index_map = predict(50)\n",
    "# 打印商品推荐字典\n",
    "predict_item_index_map"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'predict_item_index_map' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-23-5040655dbbae>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m     23\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[0munion_num\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mpredict_num\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0munion_num\u001b[0m\u001b[1;33m/\u001b[0m\u001b[0mtest_num\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     24\u001b[0m \u001b[1;31m# 计算准确率与召回率\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 25\u001b[1;33m \u001b[0mprecision\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mrecall\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcalculate_precision_and_recall\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     26\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'precision='\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mprecision\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     27\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'recall='\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mrecall\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-23-5040655dbbae>\u001b[0m in \u001b[0;36mcalculate_precision_and_recall\u001b[1;34m()\u001b[0m\n\u001b[0;32m     14\u001b[0m         \u001b[1;31m# 推荐的商品也在测试集中出现的总数做叠加\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     15\u001b[0m         union_num += len(\n\u001b[1;32m---> 16\u001b[1;33m             \u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpredict_item_index_map\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0muser_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m&\u001b[0m \u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtest_item_v\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     17\u001b[0m         )\n\u001b[0;32m     18\u001b[0m         \u001b[1;31m# 推荐的商品的总数做叠加\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'predict_item_index_map' is not defined"
     ]
    }
   ],
   "source": [
    "# 计算准确率与召回率\n",
    "def calculate_precision_and_recall():\n",
    "    # 推荐的商品也在测试集中出现的总数\n",
    "    union_num = 0\n",
    "    # 推荐的商品的总数\n",
    "    predict_num = 0\n",
    "    # 测试集中出现的商品总数\n",
    "    test_num = 0\n",
    "    # 对测试集的user_index进行遍历\n",
    "    for user_index in df_user_item_rating_test.index:\n",
    "        # 对测试集中的user_index打过分的商品，进行倒排序，得到索引\n",
    "        #（这里其实没有使用到倒序排列功能，比如可以取测试集中倒序的前100个所以test_item_v）\n",
    "        test_item_v = np.where(df_user_item_rating_test[user_index]>=3)[0].tolist()\n",
    "        # 推荐的商品也在测试集中出现的总数做叠加\n",
    "        union_num += len(\n",
    "            set(predict_item_index_map[user_index]) & set(test_item_v)\n",
    "        )\n",
    "        # 推荐的商品的总数做叠加\n",
    "        predict_num += len(predict_item_index_map[user_index])\n",
    "        # 测试集中出现的商品总数做叠加\n",
    "        test_num += len(test_item_v)\n",
    "    # 返回准确率与召回率\n",
    "    return union_num / predict_num,union_num/test_num\n",
    "# 计算准确率与召回率\n",
    "precision,recall = calculate_precision_and_recall()\n",
    "print('precision=',precision)\n",
    "print('recall=',recall)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "ename": "NameError",
     "evalue": "name 'predict_item_index_map' is not defined",
     "output_type": "error",
     "traceback": [
      "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[1;31mNameError\u001b[0m                                 Traceback (most recent call last)",
      "\u001b[1;32m<ipython-input-24-d6e7fca2a636>\u001b[0m in \u001b[0;36m<module>\u001b[1;34m\u001b[0m\n\u001b[0;32m      9\u001b[0m     \u001b[1;32mreturn\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mpredict_item_index_set\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m/\u001b[0m \u001b[0mlen\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mitem_id_s\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m     10\u001b[0m \u001b[1;31m# 计算并打印覆盖度\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 11\u001b[1;33m \u001b[0mcoverage\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mcalculate_coverage\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m     12\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m'coverage='\u001b[0m\u001b[1;33m,\u001b[0m\u001b[0mcoverage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;32m<ipython-input-24-d6e7fca2a636>\u001b[0m in \u001b[0;36mcalculate_coverage\u001b[1;34m()\u001b[0m\n\u001b[0;32m      4\u001b[0m     \u001b[0mpredict_item_index_set\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mset\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      5\u001b[0m     \u001b[1;31m# 把所有用户推荐过的商品id都添加到predict_item_index_set里，然后根据predict_item_index_set的数量，计算覆盖度\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m     \u001b[1;32mfor\u001b[0m \u001b[0muser_index\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mpredict_item_index_map\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m      7\u001b[0m         \u001b[1;32mfor\u001b[0m \u001b[0mitem_index\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mpredict_item_index_map\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0muser_index\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m      8\u001b[0m             \u001b[0mpredict_item_index_set\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mitem_index\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n",
      "\u001b[1;31mNameError\u001b[0m: name 'predict_item_index_map' is not defined"
     ]
    }
   ],
   "source": [
    "# 定义计算覆盖率\n",
    "def calculate_coverage():\n",
    "    # 推荐的物品索引集合\n",
    "    predict_item_index_set = set()\n",
    "    # 把所有用户推荐过的商品id都添加到predict_item_index_set里，然后根据predict_item_index_set的数量，计算覆盖度\n",
    "    for user_index in predict_item_index_map.keys():\n",
    "        for item_index in predict_item_index_map[user_index]:\n",
    "            predict_item_index_set.add(item_index)\n",
    "    return len(predict_item_index_set) / len(item_id_s)\n",
    "# 计算并打印覆盖度\n",
    "coverage = calculate_coverage()\n",
    "print('coverage=',coverage)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
